package com.linck.im.server.handler;

import com.linck.im.dao.SqlSessionFactoryUtil;
import com.linck.im.dao.mapper.AccountMapper;
import com.linck.im.dao.mongo.MongoDBUtil;
import com.linck.im.model.constant.Msg;
import com.linck.im.model.entity.Account;
import com.linck.im.model.proto.ProtoMsg;
import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoCollection;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.session.SqlSession;
import org.bson.Document;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 登录信息处理器
 *
 * @author: linck
 * @create: 2021-01-25
 */
@Slf4j
public class ServerLoginInfoHandler extends SimpleChannelInboundHandler<ProtoMsg.LoginInfo> {


    @Override
    protected void channelRead0(ChannelHandlerContext ctx, ProtoMsg.LoginInfo loginInfo) throws Exception {
        try (SqlSession sqlSession = SqlSessionFactoryUtil.getSqlSession()) {
            AccountMapper accountMapper = sqlSession.getMapper(AccountMapper.class);
            Account account = accountMapper.selectAccount(loginInfo.getAccount().getAccount());
            if (account == null || !loginInfo.getAccount().getPassword().equals(account.getPassword())) {
                ctx.writeAndFlush(Msg.LOGIN_FAILURE);
                log.info("{} 账户或密码错误", account.getAccount());
            } else {
                ctx.writeAndFlush(Msg.LOGIN_SUCCESS);
                // 获取离线消息
                MongoCollection<Document> messageCollection = MongoDBUtil.getMessageCollection();
                //指定查询过滤器
                FindIterable<Document> documents = messageCollection.find(new Document("to", account.getAccount()));
                List<Object> deleteIds = new ArrayList<>();
                for (Document document : documents) {
                    ProtoMsg.Message message = ProtoMsg.Message.newBuilder()
                            .setFrom((String) document.get("from"))
                            .setTo((String) document.get("to"))
                            .setTime((Long) document.get("time"))
                            .setContent((String) document.get("content"))
                            .build();
                    ctx.channel().writeAndFlush(message).addListener(channelFuture -> {
                        if (!channelFuture.isSuccess()) {
                            Object unused = channelFuture.get();
                            log.warn("发送消息失败:{}", unused);
                            // FIXME 统一发送消息出口，消息发送失败处理
                        } else {
                            log.info("离校消息发送成功");
                        }
                    });
                    deleteIds.add(document.get("_id"));
                }
                // 删除发送成功的离线消息
                if (!deleteIds.isEmpty()) {
                    messageCollection.deleteMany(new Document("_id", new Document("$in", deleteIds)));
                }

                // 获取最新好友列表
                List<ProtoMsg.Account> accountList = accountMapper.list().stream().map(t -> ProtoMsg.Account.newBuilder()
                        .setAccount(t.getAccount())
                        .build()).collect(Collectors.toList());
                ProtoMsg.Friends friends = ProtoMsg.Friends.newBuilder()
                        .addAllFriend(accountList)
                        .build();
                ctx.writeAndFlush(friends);
                ServerMessageHandler.session.put(account.getAccount(), ctx.channel().id());
                log.info("{} 登录成功", account.getAccount());
            }
        }
    }

}
